// pendingInventory.js
import { Engine } from "../engine";
import { DateUtil } from '../../utils/dateUtil';
import { CommonOrderStatus, DocType, ProgressState } from "../common/docDefinition";
import { WareHouse } from "./warehouse";
import { SubCommodity } from "../commodity/subCommodity";
import { CsDouble } from "../common/csDouble";
import { CsFundDouble } from "../common/csFundDouble";
import { DocBase } from "../common/docBase";
import { Util } from "../../utils/util";
import { TargetObject, TargetObjectType } from "../targetOrg/targetObject";
import { InventoryType } from "./inventoryType";
import { Inventory } from "./inventory";
import { InventoryInOutType } from "./inventory";
import {MeasurementUnit} from "../basicData/measurementUnit";

/// 待入待出单品信息
export class CommodityPendingBatch {
    /**
     * @param {{
     *   id: string,
     *   commodity: SubCommodity,
     *   count: CsDouble,
     *   batchPrice: CsFundDouble,
     *   singlePrice: CsFundDouble,
     *   handledCount: CsDouble
     * }} params
     */
    constructor({ id, commodity, count, batchPrice, singlePrice, handledCount, unhandledCount = null }) {
        this.commodity = commodity;  // SubCommodity
        this.id = id;
        this._count = count;   // CsDouble
        this._batchPrice = batchPrice;  // CsFundDouble
        this._singlePrice = singlePrice;  // CsFundDouble
        this._handledCount = handledCount;  // 已处理数量 CsDouble
        this._unhandledCount = unhandledCount || count.sub(handledCount);  // 未处理数量 CsDouble
        this.selected = false; // ui use

        // Validate inputs
        if (count.lt(CsDouble.zero()) || this._unhandledCount.lt(CsDouble.zero())) {
            throw new Error("Invalid count values");
        }
    }

    /// 已处理数量
    get handledCount() {
        return this._handledCount;
    }

    /// 未处理数量
    get unhandledCount() {
        return this._unhandledCount;
    }

    get count() {
        return this._count;
    }

    get singlePrice() {
        return this._singlePrice;
    }

    get batchPrice() {
        return this._batchPrice;
    }

    /// 减少数量 CsDouble
    subtractCount(subCount) {
        if (subCount.gt(CsDouble.zero())) {
            this._count = this._count.sub(subCount);
            this._count = this._count.gte(CsDouble.zero()) ? this._count : CsDouble.zero();
        }
        this._batchPrice = this._singlePrice.mul(this._count);
        return this._count;
    }

    /// 增加数量
    addCount(subCount) {
        if (subCount.gt(CsDouble.zero())) {
            this._count = this._count.add(subCount);
        }
        this._batchPrice = this._singlePrice.mul(this._count);
        return this._count;
    }

    /// 减少当前处理量
    subtractCurHandleCount(subCount) {
        if (subCount.gt(CsDouble.zero()) && this._handledCount.gte(subCount)) {
            this._handledCount = this._handledCount.sub(subCount);
            this._unhandledCount = this._count.sub(this._handledCount);
        }
        return this._handledCount;
    }

    /// 设置数量
    setCount(count) {
        if (count.gt(CsDouble.zero())) {
            this._count = count;
            this._batchPrice = this._singlePrice.mul(count);
            return this._count;
        }
        return null;
    }

    /// 设置单价
    setSinglePrice(price) {
        if (price.gte(CsFundDouble.zero())) {
            this._singlePrice = price;
            this._batchPrice = this._singlePrice.mul(this._count);
            return this._singlePrice;
        }
        return null;
    }

    /// 设置总价
    setBatchPrice(price) {
        if (price.gte(CsFundDouble.zero())) {
            this._batchPrice = price;
            if (this._count.gt(CsDouble.zero())) {
                this._singlePrice = this._batchPrice.div(this._count);
            }
            return this._singlePrice;
        }
        return null;
    }

    /// 创建商品入库批次 com : SubCommodity
    static forCommodityIn(com) {
        return new CommodityPendingBatch({
            id: "",
            count: new CsDouble(1),
            commodity: com,
            batchPrice: com.purchasePrice,
            singlePrice: com.purchasePrice,
            handledCount: CsDouble.zero(),
            unhandledCount: new CsDouble(1)
        });
    }

    /// 克隆批次
    static clone(batch) {
        return new CommodityPendingBatch({
            id: batch.id,
            count: batch._count,
            batchPrice: batch._batchPrice,
            singlePrice: batch._singlePrice,
            handledCount: batch._handledCount,
            unhandledCount: batch._unhandledCount,
            commodity: SubCommodity.clone(batch.commodity)
        });
    }

    /// 从JSON创建
    static fromJson(json) {
        const batch = new CommodityPendingBatch({
            id: Util.jsonToString(json['id']),
            count: Util.jsonToCsDouble(json["inoutStore"], 0),
            batchPrice: Util.jsonToCsFundDouble(json["inoutSumPrice"], 0),
            singlePrice: Util.jsonToCsFundDouble(json["inouttPrice"], 0),
            handledCount: Util.jsonToCsDouble(json["remaStore"], 0),
            commodity: new SubCommodity({
                name: Util.jsonToString(json['commodityName']),
                standard: Util.jsonToString(json['specName']),
                id: Util.jsonToString(json['specId']),
                commodityId: Util.jsonToString(json['commondityId']),
                unit: new MeasurementUnit({
                    id: Util.jsonToString(json['commodityUnitId']),
                    name: Util.jsonToString(json['unitName']),
                    supportDecimal: Util.jsonToBool(json['decimalSupport'], false)
                }),
                purchasePrice: Util.jsonToDouble(json['lineCostPrice'], 0),
                retailPrice: Util.jsonToDouble(json['lineRetailPrice'], 0),
                wholesalePrice: Util.jsonToDouble(json['lineTradePrice'], 0),
                imgs: Util.jsonToString(json['specImgs']),
                cost: Util.jsonToDouble(json['inoutSingleCost'], -1)
            })
        });

        if (batch._count.gt(CsDouble.zero())) {
            batch._singlePrice = batch._batchPrice.div(batch._count);
        }

        return batch;
    }

    /// 打印信息json 调试用
    toPrintInfoJson() {
        return {
            'id': this.id,
            'count': this._count,
            'batchPrice': this._batchPrice,
            'singlePrice': this._singlePrice,
            'handledCount': this._handledCount,
            'commodity': this.commodity.toJson()
        };
    }
}

/// 过滤条件
export class PendingInventoryFilter {
    /// 单号
    inventoryId = null;

    /// 单据标题
    inventoryTitle = null;

    /// 出入库状态  ProgressState
    progressState = null;

    /// 仓库  WareHouse
    wareHouse = null;

    /// 往来单位名称
    targetObjName = null;

    /// 规格商品名称
    subCommodityName = null;

    /// 开始时间
    startDate = null;

    /// 结束时间
    endDate = null;

    /// 额外过滤条件
    otherFilter = {};

    /// 门店过滤
    storeId = null;

    /**
     * @param {Object} params
     * @param {Object} [params.otherFilter={}]
     * @param {string} [params.storeId]
     */
    constructor({ otherFilter = {}, storeId = null } = {}) {
        this.otherFilter = otherFilter;
        this.storeId = storeId || Engine.profile?.filterStore?.id;
    }

    clear() {
        this.inventoryId = null;
        this.inventoryTitle = null;
        this.wareHouse = null;
        this.targetObjName = null;
        this.subCommodityName = null;
        this.startDate = null;
        this.endDate = null;
        this.progressState = null;

        // otherFilter remains unchanged
    }

    static clone(filter) {
        const cloned = new PendingInventoryFilter();
        cloned.inventoryId = filter.inventoryId;
        cloned.inventoryTitle = filter.inventoryTitle;
        cloned.wareHouse = filter.wareHouse;
        cloned.targetObjName = filter.targetObjName;
        cloned.subCommodityName = filter.subCommodityName;
        cloned.startDate = filter.startDate;
        cloned.endDate = filter.endDate;
        cloned.progressState = filter.progressState;
        cloned.otherFilter = { ...filter.otherFilter };
        cloned.storeId = filter.storeId;
        return cloned;
    }

    toJson() {
        const ret = {};

        if (this.inventoryId && this.inventoryId.length > 0) {
            ret["f_lke_id"] = this.inventoryId;
        }

        if (this.inventoryTitle && this.inventoryTitle.length > 0) {
            ret["f_lke_orderTitle"] = this.inventoryTitle;
        }

        if (this.wareHouse) {
            ret["d_storageId"] = this.wareHouse.id;
        }

        if (this.targetObjName && this.targetObjName.length > 0) {
            ret["e_lke_name"] = this.targetObjName;
        }

        if (this.subCommodityName && this.subCommodityName.length > 0) {
            ret["ign_commondityName"] = this.subCommodityName;
        }

        // 待出入库单采用记录时间
        if (this.startDate && this.endDate && this.endDate > this.startDate) {
            ret["a_gte_createTime"] = DateUtil.formatDate(this.startDate, "yyyy-MM-dd HH:mm:ss");
            ret["a_lte_createTime"] = DateUtil.formatDate(this.endDate, "yyyy-MM-dd HH:mm:ss");
        } else if (this.startDate && !this.endDate) {
            ret["a_gte_createTime"] = DateUtil.formatDate(this.startDate, "yyyy-MM-dd HH:mm:ss");
        } else if (this.endDate && !this.startDate) {
            ret["a_lte_createTime"] = DateUtil.formatDate(this.endDate, "yyyy-MM-dd HH:mm:ss");
        }

        if (this.progressState == null) {
            ret["d_neq_billStatus"] = ProgressState.AllDone.code;//Object.values(ProgressState).indexOf(ProgressState.AllDone);
        } else {
            ret["d_ign_billStatus"] = this.progressState.code;//Object.values(ProgressState).indexOf(this.progressState);
        }

        // Merge other filters
        Object.assign(ret, this.otherFilter);

        // Store filter
        if (this.storeId) {
            ret["storeId"] = this.storeId;
        }

        return ret;
    }
}

/// 待出入库记录
export class PendingInventory extends DocBase {
    /**
     * @param {Object} params
     * @param {WareHouse} params.wareHouse
     * @param {InventoryType} params.type
     * @param {ProgressState} params.progressState
     * @param {ProgressState} [params.hexiaoProgressState=ProgressState.None]
     * @param {CommodityPendingBatch[]} params.commodityList
     * @param {TargetObject} params.targetObject
     * @param {Inventory[]} [params.inventoryInList=[]]
     * @param {InventoryInOutType} params.inOutType
     * @param {string} params.id
     * @param {string} params.storeId
     * @param {string} params.storeName
     * @param {string} [params.remark=""]
     * @param {string} [params.operator=""]
     * @param {string} [params.operatorId=""]
     * @param {string} [params.docMaker=""]
     * @param {CommonOrderStatus} [params.status=CommonOrderStatus.WaitReview]
     * @param {string} [params.title=""]
     * @param {string} [params.docCode=""]
     * @param {DocType} params.parentDocType
     * @param {string} params.parentDocCode
     * @param {string} params.parentDocTitle
     * @param {DocType} params.sourceDocType
     * @param {string} params.sourceDocCode
     * @param {string} params.sourceDocTitle
     * @param {Date} [params.recordDate]
     */
    constructor({
        wareHouse,
        type,
        progressState,
        hexiaoProgressState = ProgressState.None,
        commodityList = [],  // List<CommodityPendingBatch>
        targetObject,
        inventoryInList = [],
        inOutType,  // InventoryInOutType
        estimatedCost = null,
        realCost = null,
        remainEstimatedCost = null,

        id,
        storeId,
        storeName,
        remark = "",
        operator = "",
        operatorId = "",
        docMaker = "",
        status = CommonOrderStatus.WaitReview,
        title = "",
        docCode = "",
        parentDocType,
        parentDocCode,
        parentDocTitle,
        sourceDocType,
        sourceDocCode,
        sourceDocTitle,
        recordDate
    }) {
       // if (inOutType === InventoryInOutType.Uknown) {
       //     throw new Error("Invalid inOutType");
       // }

        super({
            id,
            storeId,
            storeName,
            title,
            docCode,
            status,
            docType: inOutType === InventoryInOutType.In ? DocType.DRKD : DocType.DCKD,
            parentDocType,
            parentDocCode,
            parentDocTitle,
            sourceDocCode,
            sourceDocType,
            sourceDocTitle,
            recordDateTime: recordDate,
            operator,
            operatorId,
            docMaker,
            remark
        });

        this._commmodityList = [...commodityList]; //  List<CommodityPendingBatch>
        this.targetObject = targetObject; // 出入库使用
        this.wareHouse = wareHouse; // WareHouse
        this.type = type; // InventoryType
        this.progressState = progressState;  // 进度状态，以已审核的子单据为准 ProgressState
        this.hexiaoProgressState = hexiaoProgressState; // 单据库存核销进度状态，已子单据数量为准，不论是否审核 ProgressState
        this.inventoryInList = [...inventoryInList];  /// 入库单据 Inventory
        this.estimatedCost = estimatedCost;   /// 预估成本  CsFundDouble
        this.realCost = realCost;  /// 真实成本  CsFundDouble
        this.remainEstimatedCost = remainEstimatedCost;    /// 未出库预估成本(剩余预估成本) CsFundDouble

        this.type.inOutType = inOutType;
    }

    /**
     * @param {Object} params
     * @param {string} [params.storeId]
     * @param {string} [params.storeName]
     */
    static empty({ storeId = null, storeName = null, inOutType =  InventoryInOutType.In} = {}) {


        let instance = new PendingInventory({
            wareHouse: WareHouse.empty(),
            type: InventoryType.empty(),
            progressState: ProgressState.None,
            hexiaoProgressState: ProgressState.None,
            commodityList: [],
            inventoryInList: [],
            targetObject: TargetObject.empty({ objType: TargetObjectType.Unknown }),
            inOutType: inOutType,
            storeId: storeId,
            storeName: storeName
        });


        return instance;
    }

    /// 出入库类型
    get inOutType() {
        if (this.docType.code === DocType.DRKD.code) {
            return InventoryInOutType.In;
        } else if (this.docType.code === DocType.DCKD.code) {
            return InventoryInOutType.Out;
        }
        return InventoryInOutType.Uknown;
    }

    /// 未处理量
    getUnhandledCount() {
        let value = 0;
        for (const element of this._commmodityList) {
            value += element.unhandledCount.value;
        }
        return new CsDouble(value);
    }

    /// 商品列表 Iterable<CommodityPendingBatch>
    get commmodityList() {
        return [...this._commmodityList];
    }

    /// 插入 batch CommodityPendingBatch
    addCommodityBatch(batch) {
        this._commmodityList.push(batch);
    }

    /// 更新batch CommodityPendingBatch batch, CommodityPendingBatch orgBatch
    updateCommodityBatch(batch, orgBatch) {
        const index = this._commmodityList.indexOf(orgBatch);
        if (index >= 0) {
            this._commmodityList[index] = batch;
            return true;
        }
        return false;
    }

    /// 从JSON创建
    static fromJson(json) {

        const baseOrder = DocBase.fromJson(json);

        const pending = new PendingInventory({
            wareHouse: new WareHouse({
                id: Util.jsonToString(json['storageId']),
                name: Util.jsonToString(json['storageName'])
            }),
            type: new InventoryType({
                id: "",
                name: Util.jsonToString(json['inoutTypeName']),
                code: Util.jsonToString(json['inoutTypeCode']),
                inOutType: InventoryInOutType.Uknown
            }),
            progressState: Util.jsonToPorgressState(
                json['billStatus'],
                ProgressState.None
            ),
            hexiaoProgressState: Util.jsonToPorgressState(
                json['progressStatus'],
                ProgressState.None
            ),
            targetObject: json['objId'] == null
                ? TargetObject.empty({ objType: TargetObjectType.Unknown })
                : new TargetObject({
                    id: Util.jsonToString(json['objId']),
                    name: Util.jsonToString(json['objName']),
                    objType: TargetObjectType.Unknown
                }),
            inventoryInList: [],
            commodityList: [],
            estimatedCost: json['estimatedCost'] == null
                ? null
                : Util.jsonToCsFundDouble(json['estimatedCost'], 0),
            realCost: json['realCost'] == null
                ? null
                : Util.jsonToCsFundDouble(json['realCost'], 0),
            remainEstimatedCost: json['remainEstimatedCost'] == null
                ? null
                : Util.jsonToCsFundDouble(json['remainEstimatedCost'], 0),

            inOutType: InventoryInOutType.Uknown,
        });

        Object.assign(baseOrder, pending);

        // Add commodity batches
        const batchInRecords = json['details'] || [];
        for (const element of batchInRecords) {
            pending._commmodityList.push(CommodityPendingBatch.fromJson(element));
        }

        // Add inventory records
        const inventoryRecords = json["inoutOrders"] || [];
        for (const element of inventoryRecords) {
            pending.inventoryInList.push(Inventory.fromJson(element));
        }

        // 根据单据类型确定出入库类型
        pending.type.inOutType = pending.inOutType;

        return pending;
    }

    /// 打印信息json 调试用
    toPrintInfoJson() {
        return {
            'id': this.id,
            'title': this.title,
            'wareHouse': this.wareHouse.toJson(),
            'progressStatus': this.progressState,
            'targetObject': this.targetObject.toJson(),
            'estimatedCost': this.estimatedCost,
            'realCost': this.realCost,
            'remainEstimatedCost': this.remainEstimatedCost,
            'details': this._commmodityList.map(b => b.toPrintInfoJson())
        };
    }
}